//This file is part of o-RSA.
//
//o-RSA is free software: you can redistribute it and/or modify
//it under the terms of the GNU Lesser General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//o-RSA is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public License
//along with o-RSA.  If not, see <http://www.gnu.org/licenses/>.

#include <iostream>
#include <cstdio>
#include <time.h>
#include "cryptStream.h"
using namespace std;

#define Bunt BigUnsigned
#define Bint BigInteger

Bunt e, d, n;
string keyfilename, messagefilename;
string message;
bool en;

bool comp(string s1, string s2);
void initCMD(int argc, char* argv[]);
void initCON();
void getKey();

int main(int argc, char* argv[]){
	try{
		if(argc == 1)
			initCON();
		else
			initCMD(argc, argv);
	}
	catch(string& error){
		cout << error << endl;
		exit(1);
	}

	getKey();

	cryptStream crypt(messagefilename, "temp.txt");
	time_t startTime = time(NULL);
	if(en)
		crypt.encrypt(n, e);
	else
		crypt.decrypt(n, d);
	cout << "Elapsed time: " << time(NULL)-startTime << endl;
	remove(messagefilename.c_str());
	rename("temp.txt", messagefilename.c_str());
	while(1);
	return 0;
}

bool comp(string s1, string s2){
	if(s1.length() != s2.length())
		return false;
	for(int i = 0; i < s1.length(); i++)
		if(s1[i] != s2[i])
			return false;
	return true;
}

void getKey(){
	ifstream file;
	string temp;
	file.open(keyfilename);
	getline(file, temp);
	n = stringToBigUnsigned(temp);
	getline(file, temp);
	if(en)
		e = stringToBigUnsigned(temp);
	else
		d = stringToBigUnsigned(temp);
	file.close();
}

void initCON(){
	string temp;
	bool valid = false;
	while(!valid){
		cout << "Do you want to encrypt or decrypt? ";
		cin >> temp;
		if(comp(temp, "encrypt") || comp(temp, "e")){
			en = true;
			valid = true;
		}
		if(comp(temp, "decrypt") || comp(temp, "d")){
			en = false;
			valid = true;
		}
		if(!valid){
			cout << "Invalid selection!" << endl << endl;
		}
	}
	valid = false;
	while(!valid){
		cout << "Please enter location of the ";
		if(en)
			cout << "public key: ";
		else
			cout << "private key: ";
		cin >> temp;
		ifstream tester;
		tester.open(temp);
		if(tester.is_open()){
			valid = true;
			keyfilename = temp;
		}
		tester.close();
		if(!valid){
			cout << "Invalid file!" << endl << endl;
		}
	}
	valid = false;
	while(!valid){
		cout << "Please enter location of the file to ";
		if(en)
			cout << "encrypt: ";
		else
			cout << "decrypt: ";
		cin >> temp;
		ifstream tester;
		tester.open(temp);
		if(tester.is_open()){
			valid = true;
			messagefilename = temp;
		}
		tester.close();
		if(!valid){
			cout << "Invalid file!" << endl << endl;
		}
	}
}

void initCMD(int argc, char* argv[]){
	for(int i = 1; i < argc; i++){
		if(comp(argv[i], "-d")){
			en = false;
			i++;
			keyfilename = argv[i];
		}
		else if(comp(argv[i], "-e")){
			en = true;
			i++;
			keyfilename = argv[i];
		}
		else if(comp(argv[i], "<") || comp(argv[i], "-f")){
			i++;
			messagefilename = argv[i];
		}
		else if(argv[i][1] == '<'){
			messagefilename = string(argv[i]).substr(1, string(argv[i]).length() - 1);
		}
		else{
			throw string("Invalid command line arguments");
		}
	}
	ifstream tester;
	tester.open(keyfilename);
	if(!tester.is_open())
		throw string("Error opening file " + keyfilename);
	tester.close();
	tester.open(messagefilename);
	if(!tester.is_open())
		throw string("Error opening file " + messagefilename);
	tester.close();
}